package PrimitiveDataStructures;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * 
 * An implementation of a linked list key-value associative map data structure.
 * 
 * @author Yevgeny Levanzov & Daniel Samuelov
 *
 */
public class MyLinkedList<K,V> implements KeyValueDataStructure<K,V> {
	
	
	//a class for linked list key-value entry pair.
	private class Entry {
		
		private K key;
		private V value;
		
		/**
		 * A constructor. 
		 * 
		 * @param key the key
		 * @param val the value
		 */
		public Entry(K key, V val) {
			
			this.key = key;
			this.value = val;
		}
		
		/**
		 * Getter for key.
		 * 
		 * @return the key
		 */
		public K getKey() {
			
			return key;
		}
		
		/**
		 * Getter for value.
		 * 
		 * @return the value
		 */
		public V getValue() {
			
			return value;
		}
		
		
		/**
		 * Setter for value.
		 * 
		 * @param val the new value
		 */
		public void setValue(V val) {
			
			this.value = val;
		}
		
		/* (non-Javadoc)
		 * @see java.lang.Object#equals(java.lang.Object)
		 */
		@SuppressWarnings("unchecked")
		@Override
		public boolean equals(Object o) {
			
			return this.key.equals(((Entry)o).getKey());
		}
		
		/* (non-Javadoc)
		 * @see java.lang.Object#toString()
		 */
		@Override
		public String toString() {
			
			return "-- " + key + " --> " + value;
		}
		
	}  //end of class Entry.

	
	
	private List<Entry> lst;

	
	/**
	 * Default constructor.
	 * 
	 */
	public MyLinkedList() {
		
		this.lst = new LinkedList<Entry>();
	}
	
	
	/* (non-Javadoc)
	 * @see PrimitiveDataStructures.KeyValueDataStructure#size()
	 */
	public int size() {
		
		return this.lst.size();
	}
	

	/* (non-Javadoc)
	 * @see PrimitiveDataStructures.KeyValueDataStructure#isEmpty()
	 */
	public boolean isEmpty() {
		
		return this.lst.isEmpty();
	}
	
	

	/* (non-Javadoc)
	 * @see PrimitiveDataStructures.KeyValueDataStructure#containsKey(java.lang.Object)
	 */
	public boolean containsKey(K key) {
		
		for (Entry e : this.lst) {
			
			if (e.getKey().equals(key)){
				return true;
			}
		}
		
		return false;
	}
	

	/* (non-Javadoc)
	 * @see PrimitiveDataStructures.KeyValueDataStructure#get(java.lang.Object)
	 */
	public V get(K key) {
		
		for (Entry e : this.lst) {
			
			if (e.getKey().equals(key)){
				return e.getValue();
			}
		}
		
		return null;
	}
	

	/* (non-Javadoc)
	 * @see PrimitiveDataStructures.KeyValueDataStructure#put(java.lang.Object, java.lang.Object)
	 */
	public void put(K key, V value) {
		
		for (Entry e : this.lst) {
			
			if (e.getKey().equals(key)){
				
				e.setValue(value);  //update value.
				return;
			}
		}
		
		Entry e = new Entry(key, value);
		this.lst.add(e);

	}

	
	/* (non-Javadoc)
	 * @see PrimitiveDataStructures.KeyValueDataStructure#remove(java.lang.Object)
	 */
	public void remove(K key) {
		
		for (Entry e : this.lst) {
			
			if (e.getKey().equals(key)) {
				this.lst.remove(e);
				return;
			}
		}
		
	}
	
	/* (non-Javadoc)
	 * @see PrimitiveDataStructures.KeyValueDataStructure#keySet()
	 */
	public Set<K> keySet() {
		
		Set<K> ret = new HashSet<K>();
		
		for (Entry e : this.lst) {
			
			ret.add(e.getKey());
		}
		return ret;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		
		return lst.toString();
	}
	
}
